package org.ee.handler;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 处理netty与客户端交互
 */
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = LogManager.getLogger(NettyServerHandler.class);
    //存储所有的连接
    private static final ConcurrentHashMap<String, Channel> activeChannels = new ConcurrentHashMap<>();

    /**
     * 当客户端与服务器建立连接时，这个方法会被触发
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //super.channelActive(ctx);
        Channel channel = ctx.channel();
        //asLongText(): d8bbc1fffed8dac7-00015c4a-00000001-1fda3d26fdf100c9-b1c86c98
        //asShortText(): 133ea66b 每次打开ID都不一样
        String channelId = channel.id().asShortText();

        //获取缓冲区大小
        int recvBufSize = channel.config().getOption(ChannelOption.SO_RCVBUF);
        //加入活跃连接集合
        ctx.writeAndFlush("connection established");
        activeChannels.put(channelId, channel);

        logger.info("客户端连接成功:[{}{}],缓冲区大小:[{}],共有[{}]个客户端", channelId, channel.remoteAddress(), recvBufSize,
                activeChannels.size());


    }

    /**
     * 当通道处于 非活动 状态时，channelInactive 会被触发，表示客户端已经断开连接或网络连接中断。
     * 当客户端与服务器的连接断开时，channelInactive 会被触发
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();
        activeChannels.remove(channelId);
        logger.info("客户端断开连接:[{}-{}],共有[{}]个客户端", channelId, channel.remoteAddress(), activeChannels.size());
    }

    /**
     * 客户端异常关闭连接
     * 当发生异常时，exceptionCaught 会被调用。通常在这里处理和日志记录异常，或者关闭通道
     *
     * @param ctx
     * @param cause
     * @throws Exception
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.info("出现异常{}", cause.getMessage());
        ctx.close();
    }

    /**
     * 处理客户端发来的信息
     *
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();

        logger.info("客户端：{},状态:{},接收信息[RX]:{}", channelId, channel.isActive(), msg);
        //ctx.writeAndFlush("hello");
        // 耗时的操作可以使用异步线程
//        CompletableFuture.runAsync(() -> {
//            // 进行耗时操作
//
//        });
        // 向客户端发送消息
        String response = "Hello, client!";
        //向客户端发送消息，这里将字符串 "Hello, client!" 转换为 ByteBuf 并发送。
        ctx.writeAndFlush(Unpooled.copiedBuffer(response, CharsetUtil.UTF_8));
        logger.info("发送给客户端[{}],发送信息[TX]:{}", channelId, response);
    }

    /**
     * 当一次消息读取完成时（例如所有数据包被处理完），channelReadComplete() 会被触发。通常可以在此处调用 flush()，确保数据已被发送
     *
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
        //logger.info("数据已被发送");
    }

    /**
     * 当发生自定义事件时，这个方法会被触发。比如你可以监听超时事件等
     *
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        String channelId = channel.id().asShortText();
        if (evt instanceof IdleStateEvent event) {
            switch (event.state()) {
                case READER_IDLE:
                    logger.warn("Reader idle-no data received for a while");
                    ctx.close();
                    activeChannels.remove(channelId);
                    logger.info("{}移除客户端[{}],共有[{}]个客户端", event.state(), channelId, activeChannels.size());
                    break;
                case WRITER_IDLE:
                    logger.warn("Writer idle-no data received for a while");
                    break;
                case ALL_IDLE:
                    logger.warn("Connection is idle for too long, closing connection.");
                    ctx.close();
                    activeChannels.remove(channelId);
                    logger.info("ALL-{}移除客户端[{}],共有[{}]个客户端", event.state(), channelId, activeChannels.size());
                    break;
                default:
                    throw new IllegalStateException("Unexpected value: " + event.state());
            }
           /* idleCount++;
            logger.info("Idle count:{}", idleCount);
            if(idleCount>=MAX_COUNT){
                logger.info("Idle count exceeded limit,closing connection...");
                ctx.close().addListener(new GenericFutureListener<Future<? super Void>>() {
                    @Override
                    public void operationComplete(Future<? super Void> future) throws Exception {
                        logger.info("Connection closed due to idle timeout.");
                        activeChannels.remove(channelId);
                    }
                });
            }*/
        }
    }
}
